/**
 * Utils.js
 * Utility functions for the Virtual Bank System
 */

class Utils {
  /**
   * Format money amount with 2 decimal places and commas
   * @param {number|string} amount - The amount to format
   * @param {string} prefix - Currency symbol prefix (¥, $, €, etc.)
   * @returns {string} Formatted money string
   */
  static formatMoney(amount, prefix = '¥') {
    const num = parseFloat(amount);
    if (isNaN(num)) return `${prefix}0.00`;
    return `${prefix}${num.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,')}`;
  }

  /**
   * Format date string to localized date
   * @param {string} dateString - Date string in ISO format
   * @param {boolean} includeTime - Whether to include time
   * @returns {string} Formatted date string
   */
  static formatDate(dateString, includeTime = false) {
    if (!dateString) return '';
    
    const date = new Date(dateString);
    if (isNaN(date.getTime())) return dateString;
    
    const options = {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit'
    };
    
    if (includeTime) {
      options.hour = '2-digit';
      options.minute = '2-digit';
      options.second = '2-digit';
    }
    
    return date.toLocaleDateString('zh-CN', options);
  }

  /**
   * Calculate relative time from date
   * @param {string} dateString - Date string in ISO format
   * @returns {string} Relative time string
   */
  static getRelativeTime(dateString) {
    if (!dateString) return '';
    
    const date = new Date(dateString);
    if (isNaN(date.getTime())) return dateString;
    
    const now = new Date();
    const diff = now - date;
    
    // If less than a minute
    if (diff < 60 * 1000) {
      return '刚刚';
    }
    // If less than an hour
    else if (diff < 60 * 60 * 1000) {
      return `${Math.floor(diff / (60 * 1000))}分钟前`;
    }
    // If less than a day
    else if (diff < 24 * 60 * 60 * 1000) {
      return `${Math.floor(diff / (60 * 60 * 1000))}小时前`;
    }
    // If less than a week
    else if (diff < 7 * 24 * 60 * 60 * 1000) {
      return `${Math.floor(diff / (24 * 60 * 60 * 1000))}天前`;
    }
    // Otherwise, show the date
    else {
      return this.formatDate(dateString);
    }
  }

  /**
   * Generate a random string (for unique IDs, etc.)
   * @param {number} length - Length of the string
   * @returns {string} Random string
   */
  static randomString(length = 8) {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let result = '';
    for (let i = 0; i < length; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return result;
  }

  /**
   * Validate an email address
   * @param {string} email - Email address to validate
   * @returns {boolean} True if valid, false otherwise
   */
  static isValidEmail(email) {
    const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(String(email).toLowerCase());
  }

  /**
   * Validate a phone number (Chinese phone number format)
   * @param {string} phone - Phone number to validate
   * @returns {boolean} True if valid, false otherwise
   */
  static isValidPhoneNumber(phone) {
    const re = /^1[3-9]\d{9}$/;
    return re.test(String(phone));
  }

  /**
   * Validate a password
   * @param {string} password - Password to validate
   * @returns {boolean} True if valid, false otherwise
   */
  static isValidPassword(password) {
    // At least 8 characters, contains at least one letter and one number
    const re = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{8,}$/;
    return re.test(String(password));
  }

  /**
   * Mask sensitive information
   * @param {string} str - String to mask
   * @param {number} start - Number of characters to show at start
   * @param {number} end - Number of characters to show at end
   * @returns {string} Masked string
   */
  static maskString(str, start = 4, end = 4) {
    if (!str) return '';
    
    const len = str.length;
    if (len <= start + end) {
      return str;
    }
    
    const startStr = str.substring(0, start);
    const endStr = str.substring(len - end);
    const maskLength = len - start - end;
    const mask = '*'.repeat(maskLength);
    
    return startStr + mask + endStr;
  }

  /**
   * Mask a card number
   * @param {string} cardNumber - Card number to mask
   * @returns {string} Masked card number
   */
  static maskCardNumber(cardNumber) {
    if (!cardNumber) return '';
    return this.maskString(cardNumber, 4, 4);
  }

  /**
   * Mask a phone number
   * @param {string} phone - Phone number to mask
   * @returns {string} Masked phone number
   */
  static maskPhoneNumber(phone) {
    if (!phone) return '';
    return this.maskString(phone, 3, 4);
  }

  /**
   * Get a color based on a string (for avatar backgrounds, etc.)
   * @param {string} str - String to generate color from
   * @returns {string} HEX color
   */
  static stringToColor(str) {
    if (!str) return '#1a3a8f'; // Default color
    
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      hash = str.charCodeAt(i) + ((hash << 5) - hash);
    }
    
    let color = '#';
    for (let i = 0; i < 3; i++) {
      const value = (hash >> (i * 8)) & 0xFF;
      color += ('00' + value.toString(16)).substr(-2);
    }
    
    return color;
  }

  /**
   * Get initials from a name
   * @param {string} name - Name to get initials from
   * @returns {string} Initials
   */
  static getInitials(name) {
    if (!name) return 'U';
    
    const nameParts = name.split(' ');
    if (nameParts.length === 1) {
      return name.charAt(0).toUpperCase();
    } else {
      return (nameParts[0].charAt(0) + nameParts[nameParts.length - 1].charAt(0)).toUpperCase();
    }
  }

  /**
   * Truncate a string if it's too long
   * @param {string} str - String to truncate
   * @param {number} maxLength - Maximum length
   * @param {string} suffix - Suffix to add if truncated
   * @returns {string} Truncated string
   */
  static truncateString(str, maxLength = 30, suffix = '...') {
    if (!str) return '';
    if (str.length <= maxLength) return str;
    return str.substring(0, maxLength - suffix.length) + suffix;
  }

  /**
   * Get URL parameters
   * @param {string} url - URL to parse (defaults to current URL)
   * @returns {Object} URL parameters
   */
  static getUrlParams(url = window.location.href) {
    const params = {};
    const queryString = url.split('?')[1];
    if (!queryString) return params;
    
    const paramPairs = queryString.split('&');
    paramPairs.forEach(pair => {
      const [key, value] = pair.split('=');
      params[decodeURIComponent(key)] = decodeURIComponent(value || '');
    });
    
    return params;
  }

  /**
   * Debounce a function
   * @param {Function} func - Function to debounce
   * @param {number} wait - Wait time in milliseconds
   * @returns {Function} Debounced function
   */
  static debounce(func, wait = 300) {
    let timeout;
    return function(...args) {
      const context = this;
      clearTimeout(timeout);
      timeout = setTimeout(() => func.apply(context, args), wait);
    };
  }

  /**
   * Copy text to clipboard
   * @param {string} text - Text to copy
   * @returns {Promise} Promise that resolves when text is copied
   */
  static copyToClipboard(text) {
    if (navigator.clipboard) {
      return navigator.clipboard.writeText(text);
    } else {
      // Fallback for older browsers
      const textArea = document.createElement('textarea');
      textArea.value = text;
      textArea.style.position = 'fixed';
      document.body.appendChild(textArea);
      textArea.focus();
      textArea.select();
      
      try {
        document.execCommand('copy');
        return Promise.resolve();
      } catch (err) {
        return Promise.reject(err);
      } finally {
        document.body.removeChild(textArea);
      }
    }
  }

  /**
   * Show a toast notification
   * @param {Object} options - Toast options
   * @param {string} options.type - Toast type (success, error, warning, info)
   * @param {string} options.title - Toast title
   * @param {string} options.message - Toast message
   * @param {number} options.duration - Toast duration in milliseconds
   */
  static showToast({ type = 'info', title, message, duration = 3000 }) {
    if (window.Toast) {
      window.Toast.show({ type, title, message, duration });
    } else {
      // Create a simple toast if Toast component is not available
      const toast = document.createElement('div');
      toast.className = `toast toast-${type}`;
      toast.innerHTML = `
        <div class="toast-header">
          <span class="toast-title">${title}</span>
          <button class="toast-close">&times;</button>
        </div>
        <div class="toast-body">${message}</div>
      `;
      
      document.body.appendChild(toast);
      
      // Add some basic styling
      toast.style.position = 'fixed';
      toast.style.top = '20px';
      toast.style.right = '20px';
      toast.style.zIndex = '9999';
      toast.style.minWidth = '250px';
      toast.style.padding = '15px';
      toast.style.borderRadius = '4px';
      toast.style.boxShadow = '0 2px 8px rgba(0,0,0,0.15)';
      toast.style.backgroundColor = 'white';
      toast.style.animation = 'slideInRight 0.3s ease-out';
      
      // Close button
      const closeButton = toast.querySelector('.toast-close');
      if (closeButton) {
        closeButton.addEventListener('click', () => {
          document.body.removeChild(toast);
        });
      }
      
      // Auto-remove after duration
      setTimeout(() => {
        if (document.body.contains(toast)) {
          document.body.removeChild(toast);
        }
      }, duration);
    }
  }
}

// Export for use in other files
window.Utils = Utils;
